//
//  SOCalendar.m
//  Calendar
//
//  Created by 王文娟 on 16/7/13.
//  Copyright © 2016年 EJU. All rights reserved.
//

#import "SOCalendar.h"

static NSString *cellID = @"SOCalendar_cellID";
static NSString *headerID = @"SOCalendar_headerID";

typedef NS_ENUM(NSInteger, CalendarItemType){
    CalendarItemTypeToday = 0, //今天
    CalendarItemTypeBefore = 1,// 今天以前
    CalendarItemTypeAfter// 今天以后
};

#define itemHeight 50
#define headerReferenceHeight 44

#pragma mark - ItemModel,SectionModel
#pragma mark -

/********************************      model     *********************************************/

@interface ItemModel : NSObject

@property (nonatomic, assign) NSInteger year;
@property (nonatomic, assign) NSInteger month;
@property (nonatomic, assign) NSInteger day;
@property (nonatomic, strong) NSDate *date;
@property (nonatomic, assign) NSInteger week;
@property (nonatomic, assign) NSInteger dateInterval;
@property (nonatomic, assign) CalendarItemType type;
@property (nonatomic, assign, getter=isSelected) BOOL select;
@end

@interface SectionModel : NSObject

@property (nonatomic,copy)NSString *headerText;

/**
 *  第一天是周几
 */
@property (nonatomic, assign) NSInteger weekInFirstDay;

@property (nonatomic,strong)NSArray<ItemModel *> *itemsArray;

@end

@implementation SectionModel
@end
@implementation ItemModel
@end

#pragma mark - CalendarHeader
#pragma mark -

/********************************  CalendarHeader  ******************************/

@interface CalendarHeader : UICollectionReusableView

@property (nonatomic, weak) UILabel *monthLabel;

@property (nonatomic, assign) NSInteger weekInFirstDay;

@end

@implementation CalendarHeader


- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    
    if (self) {
        
        UILabel *monthLabel = [[UILabel alloc]init];
        
        monthLabel.textAlignment = NSTextAlignmentCenter;
        
        _monthLabel = monthLabel;
        
        [self addSubview:monthLabel];
        
    }
    return self;
}

-(void)setWeekInFirstDay:(NSInteger)weekInFirstDay{
    
    _weekInFirstDay = weekInFirstDay;
    
    self.monthLabel.frame = CGRectMake(weekInFirstDay * self.frame.size.width/7.0, 0, self.frame.size.width/7.0, self.frame.size.height);
    
}

@end

#pragma mark - SOFlowLayout
#pragma mark -


@interface SOFlowLayout : UICollectionViewFlowLayout

@end

@implementation SOFlowLayout

//虽然设置每一个cell的宽度为整个屏幕宽度／7，一行有7个cell，但是cell中间仍然存在空隙，解决方法如下：
//这里默认中间的空隙为0，可以按需求设置

-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
    
    NSArray *attributes = [super layoutAttributesForElementsInRect:rect];
    
    for(int i = 1; i < attributes.count; i++) {
        
        UICollectionViewLayoutAttributes *currentAttribute = attributes[i];
        
        if (currentAttribute.indexPath.item == 0) {
            
            continue;
        }
        UICollectionViewLayoutAttributes *preAttribute = attributes[i - 1];
        
        NSInteger maxX = CGRectGetMaxX(preAttribute.frame);
        
        if(maxX + currentAttribute.frame.size.width <= self.collectionView.frame.size.width) {
            
            CGRect frame = currentAttribute.frame;
            
            frame.origin.x = maxX;
            
            currentAttribute.frame = frame;
            
        }
        
        if (CGRectGetMaxX(currentAttribute.frame)+currentAttribute.frame.size.width>self.collectionView.frame.size.width){
            
            CGRect frame = currentAttribute.frame;
            
            frame.size.width = self.collectionView.frame.size.width - frame.origin.x;
            
            currentAttribute.frame = frame;
        
        }
    }
    
    return attributes;
    
}

@end



#pragma mark - CalendarCollectionViewCell
#pragma mark -

/********************************  CalendarCollectionViewCell  ******************************/

@interface CalendarCollectionViewCell : UICollectionViewCell

@property (nonatomic, weak) UILabel *label;

@property (nonatomic, weak) UIView *separatorLine;

@end

@implementation CalendarCollectionViewCell

- (instancetype)initWithFrame:(CGRect)frame{
    
    self = [super initWithFrame:frame];
    
    if (self) {
        
        self.backgroundColor = [UIColor lightGrayColor];
        
        UILabel *label = [[UILabel alloc]init];
        
        label.textAlignment = NSTextAlignmentCenter;
        
        _label = label;
        
        [self.contentView addSubview:label];
        
        UIView *separatorLine = [[UIView alloc]init];
        
        _separatorLine = separatorLine;
        
        [self.contentView addSubview:separatorLine];
        
    }
    return self;
}

-(void)layoutSubviews{

    [super layoutSubviews];
    
    CGFloat minLength = self.frame.size.width >self.frame.size.height?(self.frame.size.height):(self.frame.size.width);
    
    CGFloat WH = minLength*3/5.0;
    
    self.label.frame = CGRectMake(0, 0, WH, WH);
    
    self.label.center = CGPointMake(self.frame.size.width/2.0, self.frame.size.height/2.0);
    
    self.label.layer.cornerRadius = WH/2.0;
    
    self.label.clipsToBounds = YES;
    
    self.separatorLine.frame = CGRectMake(0, 0, self.frame.size.width, 1);
    

}

@end

#pragma mark - SOCalendar
#pragma mark -

/********************************   SOCalendar  *********************************************/

@interface SOCalendar()<UICollectionViewDataSource,UICollectionViewDelegate>

@property (nonatomic, weak) UICollectionView *collectionView;

@property (nonatomic, strong) SOFlowLayout *collectionViewLayout;

@property (nonatomic, strong) NSDate *todayDate;
@property (nonatomic, strong) NSDateComponents *todayCompontents;
@property (nonatomic, strong) NSCalendar *calendar;
@property (nonatomic, strong) NSDateFormatter *dateFormatter;
@property (nonatomic, strong) NSArray<SectionModel *> *sectionsArray;

@property (nonatomic, strong) NSIndexPath *showIndexPath;

@property (nonatomic, strong) NSIndexPath *selectedIndexPath;

@property (nonatomic, assign) NSInteger weekInFirstDay;

/**
 *  组的高度累计
 */
@property (nonatomic, assign) CGFloat sectionHeight;

/**
 *   每一年偏移量范围 @{ @2016:@[0,1030] , @2017 : @[1030,2360] }
 */
@property (nonatomic, strong) NSMutableDictionary *offsetRangeDic;

@end

@implementation SOCalendar

#pragma mark - init

- (instancetype)initWithFrame:(CGRect)frame{
    
    self = [super initWithFrame:frame];
    
    if (self) {
        
        [self initData];
        
        [self initBody];
        
    }
    return self;
}

-(void)initData{

    self.monthNum = 100;
    
    self.showDate = [NSDate date];
    
    self.weekdayColor = [UIColor darkGrayColor];
    
    self.weekendColor = [UIColor purpleColor];
    
    self.todayColor = [UIColor blueColor];
    
    self.selectedColor = [UIColor whiteColor];
    
    self.selectedBackgroundColor = [UIColor blueColor];
    
    self.monthColor = [UIColor blackColor];
    
    self.separatorLineColor = [UIColor colorWithWhite:0.7 alpha:0.2];
    
    self.calendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    
    self.todayDate = [NSDate date];
    
    self.todayCompontents = [self dateToComponents:self.todayDate];
    
    self.dateFormatter = [[NSDateFormatter alloc]init];
    
//    [self.dateFormatter setDateFormat: @"yyyy年MM月"];
    
    [self.dateFormatter setDateFormat: @"MM月"];

}

-(void)initBody{
    
    self.backgroundColor = [UIColor whiteColor];
    
    SOFlowLayout *layout = [[SOFlowLayout alloc]init];
    
    _collectionViewLayout = layout;
    
    layout.minimumLineSpacing = 0;
    
    layout.minimumInteritemSpacing = 0;
    
    UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:CGRectZero collectionViewLayout:layout];
    
    collectionView.alwaysBounceVertical = YES;
    
    self.collectionView = collectionView;
    
    [collectionView registerClass:[CalendarCollectionViewCell class] forCellWithReuseIdentifier:cellID];
    
    [collectionView registerClass:[CalendarHeader class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:headerID];
    
    collectionView.backgroundColor = [UIColor clearColor];
    
    collectionView.showsVerticalScrollIndicator = NO;
    
    collectionView.dataSource = self;
    
    collectionView.delegate = self;
    
    [self addSubview:collectionView];
}


-(void)layoutSubviews{
    
    [super layoutSubviews];
    
    self.collectionView.frame = self.bounds;
    
    self.collectionViewLayout.itemSize = CGSizeMake(self.bounds.size.width/7.0, itemHeight);
    
    self.collectionViewLayout.headerReferenceSize = CGSizeMake(self.bounds.size.width, headerReferenceHeight);
}

#pragma mark - lazy

-(NSMutableDictionary *)offsetRangeDic{
    
    if(_offsetRangeDic==nil){
        
        NSMutableDictionary *offsetRangeDic = [[NSMutableDictionary alloc]init];
        
        self.offsetRangeDic =  offsetRangeDic;
    }
    
    return _offsetRangeDic;
    
}

#pragma mark - method

-(void)scrollToDate:(NSDate *)date{
    
    self.showDate = date;
    
    [self reloadData];
    
}

-(void)reloadData{
    
    [self.offsetRangeDic removeAllObjects];
    
    self.sectionHeight = 0;
    
    self.sectionsArray = [self getCalendarDataSoruceWithMonthNum:self.monthNum type:self.calendarShowType];
    
    [self.collectionView reloadData];
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        
        if (self.showIndexPath) {
            
            [self.collectionView scrollToItemAtIndexPath:self.showIndexPath atScrollPosition:UICollectionViewScrollPositionTop animated:NO];
            
            self.collectionView.contentOffset = CGPointMake(0, self.collectionView.contentOffset.y - headerReferenceHeight);
            
        }

    });

}

- (NSArray *)getCalendarDataSoruceWithMonthNum:(NSInteger)monthNum type:(SOCalendarShowType)type
{
    NSMutableArray *resultArray = [[NSMutableArray alloc]init];
    
    NSDateComponents *components = [self dateToComponents:_todayDate];
    components.day = 1;
    if(type == SOCalendarShowTypeAfter){
        
        components.month -= 1;
        
    }else if(type == SOCalendarShowTypeBefore){
        
        components.month -= monthNum;
        
    }else{
        
        components.month -= (monthNum + 1) / 2;
    }
    
    NSInteger i = 0;
    
    for(i = 0;i < monthNum;i++){
        
        components.month++;
        
        SectionModel *headerItem = [[SectionModel alloc]init];
        
        NSDate *date = [self componentsToDate:components];
        
        NSString *dateString = [_dateFormatter stringFromDate:date];
        
        headerItem.headerText = dateString;
        
        self.weekInFirstDay = -1;
        
        headerItem.itemsArray = [self getCalendarItemArrayWithDate:date section:i];
        
        headerItem.weekInFirstDay = self.weekInFirstDay;
        
        [resultArray addObject:headerItem];
        
    }
    return resultArray;
}

// 得到每一天的数据源
- (NSArray *)getCalendarItemArrayWithDate:(NSDate *)date section:(NSInteger)section{
    
    NSMutableArray *resultArray = [[NSMutableArray alloc]init];
    NSInteger tatalDay = [self numberOfDaysInCurrentMonth:date];
    NSInteger firstDay = [self startDayOfWeek:date];
    
    NSDateComponents *components = [self dateToComponents:date];
    
    NSInteger tempDay = tatalDay + (firstDay - 1);
    //行数
    NSInteger rowNum = 0;
    if(tempDay % 7 == 0)
    {
        rowNum = tempDay / 7;
    }
    else
    {
        rowNum = tempDay / 7 + 1;
    }
    
    NSMutableArray *arr = self.offsetRangeDic[@(components.year)];
    
    if (!arr) {
        
        arr = [NSMutableArray array];
        
        self.offsetRangeDic[@(components.year)] = arr;
        
        [arr addObject:@(self.sectionHeight)];
        
    }
    
    self.sectionHeight += (rowNum * itemHeight + headerReferenceHeight);
    
    if (arr.count == 1) {
        
        [arr addObject:@(self.sectionHeight)];
        
    }else if (arr.count == 2){
        
        [arr replaceObjectAtIndex:1 withObject:@(self.sectionHeight)];
        
    }
    
    NSInteger i = 0;
    NSInteger j = 0;
    components.day = 0;
    for(i = 0;i < rowNum;i++){
        
        for(j = 0;j < 7;j++){
            
            if(i == 0 && j < firstDay - 1){
                
                ItemModel *calendarItem = [[ItemModel alloc]init];
                calendarItem.year = 0;
                calendarItem.month = 0;
                calendarItem.day = 0;
                calendarItem.week = -1;
                calendarItem.dateInterval = -1;
                [resultArray addObject:calendarItem];
                continue;
            }
            components.day += 1;
            if(components.day == tatalDay + 1)
            {
                i = rowNum;// 结束外层循环
                break;
            }
            ItemModel *calendarItem = [[ItemModel alloc]init];
            calendarItem.year = components.year;
            calendarItem.month = components.month;
            calendarItem.day = components.day;
            
            if (components.day == 1) {
                
                self.weekInFirstDay = j;
                
            }
            calendarItem.week = j;
            
            NSDate *theDate = [self componentsToDate:components];
            
            calendarItem.date = theDate;
            // 时间戳
            calendarItem.dateInterval = [self dateToInterval:theDate];
            
            NSDateComponents *showCompontents = [self dateToComponents:self.showDate];
            
            if (showCompontents.year == calendarItem.year && showCompontents.month == calendarItem.month && showCompontents.day == calendarItem.day) {
                
                self.showIndexPath = [NSIndexPath indexPathForRow:0 inSection:section];
                
            }
            
            if (self.selectedDate) {
                
                NSDateComponents *selectedDateCompontents = [self dateToComponents:self.selectedDate];
                
                if (selectedDateCompontents.year == calendarItem.year && selectedDateCompontents.month == calendarItem.month && selectedDateCompontents.day == calendarItem.day) {
                    
                    calendarItem.select = YES;
                    
                    self.selectedIndexPath = [NSIndexPath indexPathForRow:resultArray.count inSection:section];
                    
                }
                
            }
            
            if([date compare:_todayDate] == NSOrderedAscending){
                
                calendarItem.type = CalendarItemTypeBefore;
                
            }else{
                
                calendarItem.type = CalendarItemTypeAfter;
            }
            
            if (components.year == _todayCompontents.year && components.month == _todayCompontents.month && components.day == _todayCompontents.day){
                
                calendarItem.type = CalendarItemTypeToday;
                
            }
            
            [resultArray addObject:calendarItem];
        }
    }
    return resultArray;
}

// 一个月有多少天
- (NSUInteger)numberOfDaysInCurrentMonth:(NSDate *)date
{
    return [self.calendar rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:date].length;
}

// 确定这个月的第一天是星期几
- (NSUInteger)startDayOfWeek:(NSDate *)date
{
    NSDate *startDate = nil;
    BOOL result = [self.calendar rangeOfUnit:NSCalendarUnitMonth startDate:&startDate interval:NULL forDate:date];
    if(result)
    {
        return [self.calendar ordinalityOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitWeekOfMonth forDate:startDate];
    }
    return 0;
}

/**
 *  日期转时间戳
 */

- (NSInteger)dateToInterval:(NSDate *)date{
    
    return (long)[date timeIntervalSince1970];
    
}

-(NSInteger )getVisibleYearWithOffset:(CGFloat)offsetY{
    
    NSArray *arr = [self.offsetRangeDic allValues];
    
    NSArray *keys = [self.offsetRangeDic allKeys];
    
    NSInteger i = 0;
    
    for (NSArray *subArr in arr) {
        
        if (offsetY>=[subArr[0] floatValue] && offsetY <=[subArr[1] floatValue]) {
            
            break;
        }
        
        i++;
        
    }
    
    return [keys[i] integerValue];
}

#pragma mark - UICollectionViewDataSource

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
    
    return self.monthNum;
    
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
    
    SectionModel *model = self.sectionsArray[section];
    
    return model.itemsArray.count;
    
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
    
    CalendarCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];
    
    cell.label.backgroundColor = [UIColor clearColor];
    
    SectionModel *secModel = self.sectionsArray[indexPath.section];
    
    ItemModel *itemModel = secModel.itemsArray[indexPath.row];
    
    if (itemModel.day) {
        
        cell.label.text = [NSString stringWithFormat:@"%zd",itemModel.day];
        
        cell.userInteractionEnabled = YES;
        
        if (!self.hideSeparatorLine) {
            
            cell.separatorLine.backgroundColor = self.separatorLineColor;
            
        }else{
            
            cell.separatorLine.backgroundColor = [UIColor clearColor];
            
        }
        
        
    }else{
        
        cell.label.text = @"";
        
        cell.userInteractionEnabled = NO;
        
        cell.separatorLine.backgroundColor = [UIColor clearColor];
        
    }
    
    cell.label.textColor = self.weekdayColor;
    
    if (itemModel.week == 6 ||itemModel.week == 0) {
        
        cell.label.textColor = self.weekendColor;
        
    }
    
//    cell.backgroundColor = [UIColor lightGrayColor];
//    
//    cell.layer.borderColor = [UIColor brownColor].CGColor;
//    
//    cell.layer.borderWidth = 2;
    
    if (itemModel.type == CalendarItemTypeToday) {
        
        cell.label.textColor = self.todayColor;
        
    }
    
    if (itemModel.isSelected) {
        
        cell.label.textColor = self.selectedColor;
        
        cell.label.backgroundColor = self.selectedBackgroundColor;
        
    }
    
    
//    else if (itemModel.type == SOCalendarItemTypeBefore){
//        
//        cell.label.textColor = [UIColor redColor];
//        
//        
//    }else if (itemModel.type == SOCalendarItemTypeAfter){
//        
//        cell.label.textColor = [UIColor blackColor];
//        
//    }
    
    return cell;
    
    
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath{
    
    CalendarHeader *reusableview = nil;
    
    if (kind == UICollectionElementKindSectionHeader){
        
        reusableview = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:headerID forIndexPath:indexPath];
        
    }
    
    SectionModel *model = self.sectionsArray[indexPath.section];
    
    reusableview.monthLabel.text = model.headerText;
    
    reusableview.monthLabel.textColor = self.monthColor;
    
    reusableview.weekInFirstDay = model.weekInFirstDay;
    
    return reusableview;
    
}

//解决cell之间空隙问题无效

//- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
//    return CGSizeMake(self.bounds.size.width/7.0, itemHeight);
//}


//-(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{
//    
//    return UIEdgeInsetsMake(0, 0, 0, 0);
//}

-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
    
    if (self.selectedIndexPath && (self.selectedIndexPath.section == indexPath.section && self.selectedIndexPath.row == indexPath.row)) {
        return;
    }
    
    if (self.selectedIndexPath) {
        
        SectionModel *secModel = self.sectionsArray[self.selectedIndexPath.section];
        
        ItemModel *model = secModel.itemsArray[self.selectedIndexPath.row];
        
        model.select = NO;
        
    }
    
    SectionModel *secModel = self.sectionsArray[indexPath.section];
    
    ItemModel *model = secModel.itemsArray[indexPath.row];
    
    model.select = YES;
    
    if (self.selectedIndexPath) {
        
        [self.collectionView reloadItemsAtIndexPaths:@[self.selectedIndexPath,indexPath]];
        
    }else{
    
        [self.collectionView reloadItemsAtIndexPaths:@[indexPath]];
    }
    
    self.selectedIndexPath = indexPath;
    
    self.selectedDate = model.date;
    
    if ([self.delegate respondsToSelector:@selector(calendar:didSelectDate:)]) {
        
        [self.delegate calendar:self didSelectDate:model.date];
        
    }

}

-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
    
    if(scrollView.contentOffset.y>=0){
        
        if ([self.delegate respondsToSelector:@selector(calendar:didShowYear:)]) {
            
            [self.delegate calendar:self didShowYear:[self getVisibleYearWithOffset:scrollView.contentOffset.y]];
        }
        
        if (self.visibleYear) {
            
            self.visibleYear([self getVisibleYearWithOffset:scrollView.contentOffset.y]);
        }
    }

}



#pragma mark - NSDate - NSCompontents转换

- (NSDateComponents *)dateToComponents:(NSDate *)date{
    
    NSDateComponents *components = [self.calendar components:(NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond) fromDate:date];
    
    return components;
}

- (NSDate *)componentsToDate:(NSDateComponents *)components{
    
    components.hour = 0;
    
    components.minute = 0;
    
    components.second = 0;
    
    NSDate *date = [self.calendar dateFromComponents:components];
    
    return date;
}
@end
